package net.stevechaloner.idea.ffs.config;

import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.Icon;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.stevechaloner.idea.util.properties.DOMable;
import net.stevechaloner.idea.ffs.SearchProviderProvider;
import net.stevechaloner.idea.ffs.FirefoxSearch;

/**
 * @author Steve Chaloner
 */
public class ConfigComponent implements ProjectComponent,
                                        Configurable,
                                        JDOMExternalizable,
                                        SearchProviderProvider
{
    /**
     * The name of the component
     */
    @NonNls
    private static final String COMPONENT_NAME = "FirefoxSearchConfigComponent";

    /**
     * The display name of the component
     */
    @NonNls
    private static final String DISPLAY_NAME = "Firefox-Search";

    /**
     * The configuration GUI.
     */
    private ConfigForm form;

    /**
     * The configuration.
     */
    private final Config config = new Config();

    /**
     * 
     */
    private final Project project;

    /**
     *
     */
    private final Map<String, DOMable> domables = new HashMap<String, DOMable>()
    {
        {
            put(config.getName(),
                config);
        }
    };

    private final List<ConfigListener> configListeners = new ArrayList<ConfigListener>();

    /**
     *
     * @param project the project
     */
    public ConfigComponent(@NotNull Project project)
    {
        this.project = project;
    }

    // javadoc inherited
    public void initComponent()
    {
    }

    // javadoc inherited
    public void disposeComponent()
    {
    }

    // javadoc inherited
    @NotNull
    public String getComponentName()
    {
        return COMPONENT_NAME;
    }

    // javadoc inherited
    public void projectOpened()
    {
        // called when project is opened
    }

    // javadoc inherited
    public void projectClosed()
    {
        // called when project is being closed
    }

    @Nls
    public String getDisplayName()
    {
        return DISPLAY_NAME;
    }

    // javadoc inherited
    public Icon getIcon()
    {
        return null;
    }

    @Nullable
    @NonNls
    public String getHelpTopic()
    {
        return null;
    }

    // javadoc inherited
    public JComponent createComponent()
    {
        if (form == null)
        {
            form = new ConfigForm(project,
                                  this);
        }
        return form.getRootComponent();
    }

    // javadoc inherited
    public boolean isModified()
    {
        return form != null && form.isModified(config);
    }

    // javadoc inherited
    public void apply() throws ConfigurationException
    {
        if (form != null)
        {
            form.getData(config);
            for (ConfigListener configListener : configListeners)
            {
                configListener.configUpdated(this,
                                             config);
            }
        }
    }

    // javadoc inherited
    public void reset()
    {
        if (form != null)
        {
            form.setData(config);
        }
    }

    // javadoc inherited
    public void disposeUIResources()
    {
        form = null;
    }

    // javadoc inherited
    public void readExternal(Element element) throws InvalidDataException
    {
        for (String key : domables.keySet())
        {
            DOMable domable = domables.get(key);
            Element child = element.getChild(key);
            if (child == null)
            {
                child = new Element(key);
                element.addContent(child);
            }
            domable.read(child);
        }
    }

    // javadoc inherited
    public void writeExternal(Element element) throws WriteExternalException
    {
        for (String key : domables.keySet())
        {
            DOMable domable = domables.get(key);
            element.addContent(domable.write());
        }
    }

    // javadoc unnecessary
    public Config getConfig()
    {
        return config;
    }

    // javadoc unnecessary
    public void addConfigListener(@NotNull ConfigListener configListener)
    {
        configListeners.add(configListener);
    }

    // javadoc unnecessary
    public boolean removeConfigListener(@NotNull ConfigListener configListener)
    {
        return configListeners.remove(configListener);
    }

    // javadoc inherited
    @NotNull
    public List<String> getSearchProviderNames()
    {
        FirefoxSearch search = project.getComponent(FirefoxSearch.class);
        return search.getSearchProviderNames();
    }
}
